import Vue from 'vue'

// 引入vue-router，vue的官方路由
import Router from 'vue-router'

/*
  * 懒加载(按需加载)
  * 把不同路由对应的组件分割成不同的代码块，然后当路由被访问的时候才加载对应组件
  * 1、Vue异步组件(涉及promise函数) 例子在home.vue中查看
    {
      components:{
        custom:(resolve, reject) => {}
      }
    }

  * 2、webpack代码分割功能 
      2.1、require.ensure代码分块
        require.ensure(依赖, 回调函数, [chunk名字])   // 如果设置了chunk名字，webpack会按照相同的chunk名字把两个模块打包在一起
      2.2、import函数
*/

// 引入组件(使用webpack的代码分割功能)
let home = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/components/home'));
  })
}
// 我们也可以使用import (更简单，但是import不支持把两个模块打包在一起。不过未来可能会完全使用import代替ensure)
let about = (resolve, reject) => {
  return import('@/components/about');
}
let document = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/components/document'));
  })
}
let user = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/components/user'));
  })
}
let notFound = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/components/404'));
  })
}
let login = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/components/login'));
  })
}

let study = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/views/study'));
  })
}
let work = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/views/work'));
  })
}
let hobby = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/views/hobby'));
  })
}

let slider = (resolve, reject) => {
  return require.ensure([], () => {
    resolve(require('@/views/slider'));
  })
}

// Vue安装路由插件
Vue.use(Router)


/*
  * main.js文件中注入了router对象
  * $router router实例对象
  * $route  当前激活路由信息对象，每个组件实例都会有路由信息对象
*/


/*  我们打印出路由信息对象$route，可以看到有很多的属性：
  * path 字符串 对应当前路由的路径
  * params 对象 包含动态路由参数 (常用)
  * query 对象 URL查询参数
  * hash 字符串 当前路由的hash值
  * fullPath 字符串 URL包含查询参数和hash的完整路径
  * matched 数组 包含当前路由的所有嵌套路径片段的路由记录
  * name 字符串 当前路由的名称
  * meta 对象 可以自己配置一些数据来使用(比如是否需要登陆，设置路由拦截)，用在路由信息对象中 (常用)
*/


/*
  * 除了使用router-link标签来导航，我们也可以使用“编程式导航”，通过编写代码来实现导航的切换
  * 借助于router实例，我们可以使用以下几个方法：
  * back     回退一步
  * forward  前进一步
  * go       指定前进、回退步数
  * push     导航到不同url，并且向history栈添加一个新记录 (常用)
  * replace  导航到不同url，替换history栈中的当前记录
*/


/*
  * 导航钩子函数：导航发生变化时，导航钩子主要用来拦截导航，让它完成跳转或取消

  * 执行钩子函数的位置
    1、router全局
    2、单个路由
    3、组件中

  * 钩子函数：
    router实例上（全局）：beforeEach、afterEach
    单个路由中：beforeEnter (写在路由规则配置中)
    组件内的钩子：beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave (写在组件中)

  * 钩子函数接收的参数：
    to：   要进入的目标的路由对象 到哪里去
    from： 正要离开导航的路由对象 从哪里来
    next： 决定跳转或取消导航，接收各种参数，具体查看vue-router的文档  

  * 完整的导航解析(顺序)流程：
      导航被触发。
      在失活的组件里调用离开守卫。
      调用全局的 beforeEach 守卫。
      在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
      在路由配置里调用 beforeEnter。
      解析异步路由组件。
      在被激活的组件里调用 beforeRouteEnter。
      调用全局的 beforeResolve 守卫 (2.5+)。
      导航被确认。
      调用全局的 afterEach 钩子。
      触发 DOM 更新。
      用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
*/

let router = new Router({

  // 默认哈希模式#，我们可以改为history模式，需要服务端配合
  mode: "history",

  // 自定义当前激活的路由的样式名称
  linkActiveClass: 'is-active',

  // 滚动(条)行为  我们可以保存滚动条的位置
  // 点击浏览器的前进后退按钮、路由导航的时候触发滚动行为
  scrollBehavior(to, from, savePosition){

    // to：进入的目标路由对象
    // from：离开的路由对象
    // savePosition：记录滚动条的坐标，点击前进后退的时候才有值

    // console.log(to);
    // console.log(from);
    // console.log(savePosition);

    if (savePosition) {
        return savePosition
    }else{
        return { x: 0, y: 0 }
    }
    // tips:我们可以使用哈希#来定位到某个元素，元素设置id，这里就不细述了。
  },

  // 路由规则的配置
  routes: [
    {
      // 路径url
      path: '/',
      // 路由的命名导航
      // name: 'login',
      // 路由匹配渲染的组件
      component: login,
      // meta可以自定义配置数据
      meta: {
        login: true,
        title: 'login'
      },
      redirect: '/login',
    },
    {
      path: '/home',
      name: 'home',
      component: home,
      // alias：路由的别名，输入别名时，路由会渲染对应的相同的组件
      alias: '/index',
      meta: {
        index: 0,
        login: true,
        title: 'home'
      },
    },
    {
      path: '/document',
      name: 'document',
      beforeEnter(to, from, next){
        console.log("进入单个路由之前的钩子函数");
        next();
      },
      // 对应多个组件，注意这里是components，复数形式
      components: {
        // default对应默认的组件
        default: document,
        // 这里就是命名视图，key对应router-view的name的值，value对应组件的名称
        slider: slider,
      },
      meta: {
        index: 1,
        // 假如document是需要登陆状态才能访问的，并且我们在路由全局钩子函数中login配置了true的话，可以实现判断登录状态。请到下面的钩子函数中查看
        login: true,
        title: 'document'
      }
    },
    {
      path: '/about',
      // name: 'about',
      component: about,
      // 子路由
      children: [
        {
          // 默认的子路由(tips：父组件和这个子组件是一起被渲染的)
          path: '',
          name: 'about',
          component: study,
          meta: {
            index: 2,
            login: true,
            title: 'about'
          }
        },
        {
          path: 'work',
          name: 'work',
          component: work,
        },
        {
          path: 'hobby',
          name: 'hobby',
          component: hobby,
        }
      ],
    },
    {
      // 动态添加路径的参数，请看user.vue文件
      path: '/user/:tip?/:userId?',
      name: 'user',
      component: user,
      meta: {
        index: 3,
        login: true,
        title: 'user'
      }
    },
    {
      path: '/login',
      name: 'login',
      component: login,
      meta: {
        title: 'login'
      }
    },

    // 假如输入了错误地址
    {
      path: '*',
      component: notFound,

      // 重定向（string或者对象形式）
      // redirect: '/home',
      // redirect: {path: '/home'},
      // redirect: {name: 'home'},

      // 动态设置重定向目标
      // redirect: (to) => {
      //   // to:目标路由对象中访问的路径的路由信息
      //   // console.log(to);
      //   if(to.path == '/123'){
      //     return '/home'
      //   }
      // },
      meta:{
        title: '404'
      }
    }
  ]

})

// 全局导航跳转之前和之后的钩子函数
router.beforeEach((to, from, next) => {
  // 假如访问的路径需要登陆，那么我们可以使用这个钩子函数来判断是否拦截
  if(to.meta.login){
    // 我们在点击跳转的路由的配置中meta.login设置为true，实现(document)需要登陆状态才能访问，否则重定向到登录页面
    // router.app指向Vue根实例
    if(router.app.$local.fetch('userId')){
      let userId = router.app.$local.fetch('userId').login;
      if(userId){
        next();
      }else {
        next('/login');
      }
    }else {
      next('/login');
    }
  }else {
    next();
  }
  
})
router.afterEach((to, from) => {
  if(to.meta.title){
    window.document.title = to.meta.title;
  }else {
    window.document.title = '404,找不到页面';
  }
})

// 导出路由的实例对象
export default router